#include <cstdio>
#include <cstring>
#include <vector>

#include "camera.h"

#include "geometry.h"
#include "linear_aggr.h"
#include "uniform_grid.h"
#include "bvh.h"

#include "light.h"
#include "material.h"

#include "sampler.h"
#include "integrater.h"

using namespace tls;
using namespace std;

int main(int argc,char* argv[]){
  if(argc<2) return 0;

  FILE* file=fopen(argv[1],"r");

  int n_samples;
  int n_lights,n_materials,n_objs;

  fscanf(file,"%d",&n_samples);
  fscanf(file,"%d%d%d",&n_lights,&n_materials,&n_objs);


  //camera
  real m[16];
  real fov;
  real sizex,sizey;
  int w,h;
  for(int i=0;i<16;++i) fscanf(file,"%lf",m+i);
  fscanf(file,"%lf",&fov);fov=fov/180 * pi;
  fscanf(file,"%lf%lf",&sizex,&sizey);
  fscanf(file,"%d%d",&w,&h);
  camera* cam=new camera(sizex,sizey,mat4x4(m),fov,w,h);

  //lights
  vector<light*> lights;
  for(int i=0;i<n_lights;++i){
    vec3 pos,it;
    fscanf(file,"%lf%lf%lf",&pos.x,&pos.y,&pos.z);
    fscanf(file,"%lf%lf%lf",&it.x,&it.y,&it.z);
    lights.push_back(new point_light(pos,it));
  }

  //materials
  vector<material*> materials;
  for(int i=0;i<n_materials;++i){
    vec3 r;
    fscanf(file,"%lf%lf%lf",&r.x,&r.y,&r.z);
    materials.push_back(new matte(r));
  }

  //objs
  linear_aggr aggr;
  int fbase=0;
  vector<int> mats;
  vector<mesh::tuple> faces;

  for(int i=0;i<n_objs;++i){
    int mat_index;
    for(int j=0;j<16;++j) fscanf(file,"%lf",m+j);
    fscanf(file,"%d",&mat_index);

    char filename[32];
    fscanf(file,"%s",filename);
    FILE* fmodel=fopen(filename,"r");

    mesh* geom=(mesh*)create_mesh(fmodel);
    fclose(fmodel);

    mat4x4 T(m);
    for(int j=0;j<geom->n_verts;++j)
      geom->verts[j]=T * geom->verts[j];
    aggr.verts.insert(aggr.verts.end(),geom->verts,geom->verts+geom->n_verts);

    for(int j=0;j<geom->n_faces;++j){
      mats.push_back(mat_index);
      geom->faces[j].a+=fbase;
      geom->faces[j].b+=fbase;
      geom->faces[j].c+=fbase;
    }
    faces.insert(faces.end(),geom->faces,geom->faces+geom->n_faces);

    fbase+=geom->n_verts;
    delete geom;
  }
  for(int i=0;i<faces.size();++i){
    const vec4* a=&aggr.verts[faces[i].a];
    const vec4* b=&aggr.verts[faces[i].b];
    const vec4* c=&aggr.verts[faces[i].c];
    aggr.faces.push_back(triangle(a,b,c,materials[mats[i]]));
  }


  diffuse* simple=new diffuse();
  simple->aggr=new bvh(aggr);
  simple->cam=cam;
  simple->samp=new jitter(n_samples);
  simple->lights=lights;
  simple->mats=materials;

  simple->render();
  simple->cam->f.process();
  simple->cam->f.write("image.png");

  delete simple;
  return 0;
}

